package com.jwater.core.manager.common.conf;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jwater.core.common.param.ParamMap;
import com.jwater.core.common.param.ParamMapImpl;
import com.jwater.core.common.xml.XmlConfig;
import com.jwater.core.manager.common.DataKeys;
import com.jwater.core.manager.common.model.WorkerInfo;
import com.jwater.launch.DeployPathUtils;
import com.jwater.launch.HomePath;

/**
 * @description:工作进程配置解析器
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class WorkerConfParse {
    protected static Logger logger = LoggerFactory.getLogger(WorkerConfParse.class);
    protected Map<String, WorkerInfo> workerInfos = new ConcurrentHashMap<>();

    /**
     * 获取安装包路径
     *
     * @param regionName
     * @param deployName
     * @return
     */
    public static File getDeployPath(String regionName, String deployName) {
        ParamMap infoProps = parseInfo(regionName, deployName);
        Long version = null;
        if (infoProps != null) {
            version = infoProps.getLong("version");
        }
        return DeployPathUtils.getDeployPath(regionName, deployName, version);
    }

    /**
     * 解析
     *
     * @param regionName
     * @param deployName
     * @return
     */
    public static ParamMap parseInfo(String regionName, String deployName) {
        Map<String, Object> map = new HashMap<>();
        String infoXmlPath = HomePath.getWorkerInfoPath(regionName, deployName);
        try {
            XmlConfig config = new XmlConfig();
            config.loadConfig(infoXmlPath);
            List<ParamMap> infoProps = config.getParamMapsByPath("jwater/props/prop");
            if (infoProps != null) {
                for (ParamMap infoProp : infoProps) {
                    map.put(infoProp.getString("key"), infoProp.getString("value"));
                }
            }
        } catch (Exception e) {
            logger.error("parse error for:" + infoXmlPath, e);
        }
        return ParamMapImpl.wrap(map);
    }

    /**
     * 获取工作进程配置
     *
     * @return
     */
    public Collection<WorkerInfo> getWorkerInfos() {
        return workerInfos.values();
    }

    /**
     * 获取工作进程配置
     *
     * @param regionName
     * @param deployName
     * @param groupName
     * @param workerName
     * @return
     */
    public WorkerInfo getWorkerInfo(String regionName, String deployName, String groupName, String workerName) {
        String workerKey = DataKeys.getWorkerKey(regionName, deployName, groupName, workerName);
        return workerInfos.get(workerKey);
    }

    /**
     * 获取工作进程配置
     *
     * @param regionName
     * @return
     */
    public List<WorkerInfo> getRegionWorkerInfo(String regionName) {
        List<WorkerInfo> list = new ArrayList<>();
        for (WorkerInfo workerInfo : workerInfos.values()) {
            if (regionName.equals(workerInfo.getRegionName())) {
                list.add(workerInfo);
            }
        }
        return list;
    }

    /**
     * 获取工作进程配置
     *
     * @param regionName
     * @param deployName
     * @return
     */
    public List<WorkerInfo> getDeployWorkerInfo(String regionName, String deployName) {
        List<WorkerInfo> list = new ArrayList<>();
        for (WorkerInfo workerInfo : workerInfos.values()) {
            if (regionName.equals(workerInfo.getRegionName()) && deployName.equals(workerInfo.getDeployName())) {
                list.add(workerInfo);
            }
        }
        return list;
    }

    /**
     * 获取工作进程配置
     *
     * @param regionName
     * @param deployName
     * @param groupName
     * @return
     */
    public List<WorkerInfo> getGroupWorkerInfo(String regionName, String deployName, String groupName) {
        List<WorkerInfo> list = new ArrayList<>();
        for (WorkerInfo workerInfo : workerInfos.values()) {
            if (regionName.equals(workerInfo.getRegionName()) && deployName.equals(workerInfo.getDeployName())
                    && groupName.equals(workerInfo.getGroupName())) {
                list.add(workerInfo);
            }
        }
        return list;
    }

    /**
     * 添加工作进程
     *
     * @param workerInfo
     */
    public void addWorkerInfo(WorkerInfo workerInfo) {
        String workerKey = DataKeys.getWorkerKey(workerInfo.getRegionName(), workerInfo.getDeployName(),
                workerInfo.getGroupName(), workerInfo.getWorkerName());
        workerInfos.put(workerKey, workerInfo);
    }

    /**
     * 移除工作进程
     *
     * @param workerInfo
     */
    public void removeWorkerInfo(WorkerInfo workerInfo) {
        String workerKey = DataKeys.getWorkerKey(workerInfo.getRegionName(), workerInfo.getDeployName(),
                workerInfo.getGroupName(), workerInfo.getWorkerName());
        workerInfos.remove(workerKey);
    }

    /**
     * 移除工作进程
     *
     * @param workerInfo
     */
    public void removeGroupWorker(WorkerInfo workerInfo) {
        List<WorkerInfo> removeWorkers = getGroupWorkerInfo(workerInfo.getRegionName(), workerInfo.getDeployName(),
                workerInfo.getGroupName());
        for (WorkerInfo removeWorker : removeWorkers) {
            String workerKey = DataKeys.getWorkerKey(removeWorker.getRegionName(), removeWorker.getDeployName(),
                    removeWorker.getGroupName(), removeWorker.getWorkerName());
            workerInfos.remove(workerKey);
        }
    }

    /**
     * 解析
     */
    public void parse() {
        List<String> regionNames = HomePath.getRegionNames();
        regionNames.forEach(this::parseRegion);
    }

    /**
     * 按照域解析
     *
     * @param regionName
     */
    public void parseRegion(String regionName) {
        List<String> deployNames = HomePath.getDeployNames(regionName);
        for (String deployName : deployNames) {
            parseDeploy(regionName, deployName);
        }
        // 移除已经消失的deployName
        removeExclude(deployNames, regionName);
    }

    /**
     * 排除失效项目
     *
     * @param deployNames
     */
    private void removeExclude(List<String> deployNames, String regionName) {
        Iterator<Entry<String, WorkerInfo>> it = workerInfos.entrySet().iterator();
        while (it.hasNext()) {
            WorkerInfo workerInfo = it.next().getValue();
            if (!deployNames.contains(workerInfo.getDeployName()) && workerInfo.getRegionName().equals(regionName)) {
                it.remove();
            }
        }
    }

    /**
     * 解析安装包下的
     *
     * @param regionName
     * @param deployName
     * @return
     */
    public List<String> parseDeploy(String regionName, String deployName) {
        ParamMap infoProps = parseInfo(regionName, deployName);
        Long version = null;
        if (infoProps != null) {
            version = infoProps.getLong("version");
        }
        File deployPath = DeployPathUtils.getDeployPath(regionName, deployName, version);
        if (deployPath == null) {
            logger.warn("can not find worker deploy path for:" + regionName + "," + deployName + "," + version);
            return new ArrayList<String>();
        }
        String workerXmlPath = HomePath.getWorkerXmlPath(deployPath.getPath());
        try {
            XmlConfig config = new XmlConfig();
            config.loadConfig(workerXmlPath);
            List<ParamMap> groups = config.getParamMapsByPath("jwater/workerGroup");
            if (groups == null) {
                return new ArrayList<String>();
            }
            return parseGroup(regionName, deployName, infoProps, groups);
        } catch (Exception e) {
            logger.error("parse error for:" + workerXmlPath, e);
        }
        return new ArrayList<String>();
    }

    /**
     * 支持文件的重复解析
     *
     * @param regionName
     * @param deployName
     * @param infoProps
     * @param groups
     */
    private List<String> parseGroup(String regionName, String deployName, ParamMap infoProps, List<ParamMap> groups) {
        List<String> workerKeys = new ArrayList<String>();
        // 标记删除
        List<WorkerInfo> removeWorkers = getDeployWorkerInfo(regionName, deployName);
        Set<String> removeKeys = new HashSet<>();
        for (WorkerInfo removeWorker : removeWorkers) {
            String workerKey = DataKeys.getWorkerKey(regionName, deployName, removeWorker.getGroupName(),
                    removeWorker.getWorkerName());
            removeKeys.add(workerKey);
        }
        // 解析
        for (ParamMap group : groups) {
            String groupName = group.getString("groupName");
            String groupDesc = group.getString("desc");
            List<ParamMap> workers = group.getParamMaps("worker");
            int sn = 0;
            for (ParamMap worker : workers) {
                sn++;
                String workerName = worker.getString("workerName");
                String className = worker.getString("class");
                String workerDesc = worker.getString("desc");
                ParamMap props = parseWorkerProps(worker);
                WorkerInfo workerInfo = new WorkerInfo();
                workerInfo.setSn(sn);
                workerInfo.setRegionName(regionName);
                workerInfo.setDeployName(deployName);
                workerInfo.setGroupName(groupName);
                workerInfo.setWorkerName(workerName);
                workerInfo.setClassName(className);
                workerInfo.setGroupDesc(groupDesc);
                workerInfo.setWorkerDesc(workerDesc);
                workerInfo.setInfoProps(infoProps);
                workerInfo.setProps(props);
                String workerKey = DataKeys.getWorkerKey(regionName, deployName, groupName, workerName);
                workerInfos.put(workerKey, workerInfo);
                workerKeys.add(workerKey);
                removeKeys.remove(workerKey);
            }
        }
        // 删除
        removeKeys.forEach((key) -> {
            workerInfos.remove(key);
        });
        return workerKeys;
    }

    /**
     * 解析属性
     *
     * @param worker
     * @return
     */
    public static ParamMap parseWorkerProps(ParamMap worker) {
        Map<String, Object> map = new HashMap<>();
        List<ParamMap> props = worker.getParamMaps("prop");
        for (ParamMap prop : props) {
            map.put(prop.getString("key"), prop.getString("value"));
        }
        return ParamMapImpl.wrap(map);
    }
}
